package com.xunmeng.chapter2;

import io.netty.buffer.ByteBuf;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * 非阻塞
 */
@Slf4j
public class SelectorNBlockServer {


    private static void split(ByteBuffer sourse){
        // 将sourse切换到读模式
        sourse.flip();
        for(int i=0;i<sourse.limit();i++){
            if(sourse.get(i)=='\n'){// 说明到了分割符号
                // 长度=结尾-开头
                int length=i-sourse.position()+1;
                // 创建buteBuffer
                ByteBuffer buffer=ByteBuffer.allocate(length);
                for(int j=0;j<length;j++){
                    buffer.put(sourse.get());
                }
                buffer.flip();
                // 打印buyteBuffer
                System.out.print(StandardCharsets.UTF_8.decode(buffer));
            }
        }
        sourse.compact();
    }

    public static void main(String[] args) throws IOException {
        // 创建Selector，管理多个channel
        Selector selector=Selector.open();
        ServerSocketChannel ssc=ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ssc.bind(new InetSocketAddress(8080));
        // 将该ssc channel与 selector绑定
        SelectionKey sscKey = ssc.register(selector, 0, null);
        // ssc只关注accept事件
        sscKey.interestOps(SelectionKey.OP_ACCEPT);
        log.info("成功建立开启服务。。。。。。。");
        log.debug("register ssc key:{}",sscKey);
        while (true){
            // select 方法，没有事件发生，线程阻塞，有事件发生执行
            selector.select();
            // selectionKeys 内部包含了所有发生的事件
            Iterator<SelectionKey> selectionKeysIterator = selector.selectedKeys().iterator();
            while (selectionKeysIterator.hasNext()){
                SelectionKey key = selectionKeysIterator.next();
                // 处理key的时候要从selectedKeys中删除
                selectionKeysIterator.remove();
                log.debug("key：{}",key);
                // 判断当前key是触发了什么事件
                if(key.isAcceptable()){
                    ServerSocketChannel channel = (ServerSocketChannel)key.channel();
                    SocketChannel sc = channel.accept();// 获取到了连接
                    // 将该sc绑定read事件
                    sc.configureBlocking(false);
                    SelectionKey scKey = sc.register(selector, 0, ByteBuffer.allocate(5));
                    // 绑定事件
                    scKey.interestOps(SelectionKey.OP_READ);
                    log.debug("{}",sc);
                }else if (key.isReadable()){
                    try {
                        SocketChannel sc = (SocketChannel) key.channel();
                        ByteBuffer buffer= (ByteBuffer) key.attachment();
                        int read = sc.read(buffer);// 当客户端关闭连接后会报错
                        if(read==-1){
                            key.cancel();
                        }else {
                            split(buffer);
                            // 判断是否满容
                            if (buffer.limit()==buffer.position()){
                                // 扩容
                                ByteBuffer newbuffer=ByteBuffer.allocate(buffer.capacity()*2);
                                buffer.flip();
                                newbuffer.put(buffer);
                                key.attach(newbuffer);
                            }

                        }
                    }catch (Exception e){
                        e.printStackTrace();
                        key.cancel();
                    }
                }
            }
        }

    }
}
